#include "mbreghandler.h"
#include <QDebug>
//#include <TSettings>
#include "common/common.h"
//#include "tscalenew.h"
#include "mainwidget.h"
#include "common/tsettings/tsettings.h"

#define MODBUS_GRP  "modubs"
#define ENDIAN_MODE "endian"
#define CAL_SUCCESS "endian"
MBRegHandler *MBRegHandler::mHandler = NULL;
MBRegHandler::MBRegHandler(MainWidget *parent) :QObject(parent)
{
    TSettings set(DIR_SETTINGS,TSettings::IniFormat);
    set.beginGroup(MODBUS_GRP);
    mEndian =(EndianMode)set.value(ENDIAN_MODE,ENDIAN_MODE_SMALL).toInt();
    mCalSuccess = set.value(CAL_SUCCESS,true).toBool();
    connect(this,SIGNAL(sTare(bool)),parent,SLOT(tareScale()));
    connect(this,SIGNAL(sZero()),parent,SLOT(zeroScale()));
    connect(this,SIGNAL(sSetAdw(float)),this,SLOT(setAdw(float)));
    connect(this,SIGNAL(sPretare(float)),parent,SLOT(preTareScale(float)));
    connect(this,SIGNAL(sSetHi(float)),this,SLOT(setHi(float)));
    connect(this,SIGNAL(sSetLow(float)),this,SLOT(setLow(float)));
    //mScale = TScaleNew::getScale();
    mScaleAdaptor = SpScaleAdaptor::getInstance();
}


const  INPUT_REG MBRegHandler::mb_tab_input_reg[]={
    1,  MB_INT,     &MBRegHandler::MB_getScaleSatus,
    2,  MB_FLOAT,   &MBRegHandler::MB_getFloatNet,
    4,  MB_FLOAT,   &MBRegHandler::MB_getFloatGross,
    6,  MB_FLOAT,   &MBRegHandler::MB_getFloatTare,
    8,  MB_INT,     &MBRegHandler::MB_getUnit,
    9,  MB_INT,     &MBRegHandler::MB_getDeci,
/////////////////////////////////////////////////////////////
//    10, MB_LONG,    &MBRegHandler::MB_getLongNet,
//    12, MB_LONG,    &MBRegHandler::MB_getLongGross,
//    14, MB_LONG,    &MBRegHandler::MB_getLongTare,
//    16, MB_LONG,    &MBRegHandler::MB_getLongFull,
    0,
};

const  HOLDING_REG MBRegHandler::mb_tab_holding_reg[]={
    1,  MB_FLOAT,   &MBRegHandler::MB_getFloatTare,    &MBRegHandler::MB_setFloatTare,
    3,  MB_FLOAT,   &MBRegHandler::MB_getFloatHi,      &MBRegHandler::MB_setFloatHi,
    5,  MB_FLOAT,   &MBRegHandler::MB_getFloatLo,      &MBRegHandler::MB_setFloatLo,
    7,  MB_FLOAT,   &MBRegHandler::MB_getCalWgt,       &MBRegHandler::MB_setCalWgt,

    //9,  MB_INT,     &MBRegHandler::MB_getDevAddr,      &MBRegHandler::MB_setDevAddr,
   // 7,  MB_INT,     &MBRegHandler::MB_getDeci,         &MBRegHandler::MB_setDeci,
   // 8,  MB_INT,     &MBRegHandler::MB_getDiv,          &MBRegHandler::MB_setDiv,
  //  9,  MB_FLOAT,   &MBRegHandler::MB_getFloatFull,    &MBRegHandler::MB_setFloatFull,

    0
};


const SINGLE_COIL MBRegHandler::mb_tab_coil_reg[]={
    1,  &MBRegHandler::MB_getEndian,    &MBRegHandler::MB_setEndian,
    2,  &MBRegHandler::MB_getZeroFlag,     &MBRegHandler::MB_setZeroFlag,
    3,  &MBRegHandler::MB_getTareFlag,     &MBRegHandler::MB_setTareFlag,
    0,
};


const DISCRETE_INPUT MBRegHandler::mb_tab_discrete_reg[]={
    1,  &MBRegHandler::MB_getStabFlag,
    2,  &MBRegHandler::MB_getZeroFlag,
    3,  &MBRegHandler::MB_getTareFlag,
    4,  &MBRegHandler::MB_getOverLoadFlag,
    5,  &MBRegHandler::MB_getLoFlag,
    6,  &MBRegHandler::MB_getOkFlag,
    7,  &MBRegHandler::MB_getHiFlag,
    8,  &MBRegHandler::MB_getCalSuccess,

    0,
};



eMBErrorCode MBRegHandler::eMBRegInputCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNRegs)
{
    int    len, reg;
    const INPUT_REG *pr;
	for ( pr=mb_tab_input_reg; pr->reg_no>0; pr++){

		if (usAddress == pr->reg_no){
            reg = pr->size;
            if (usNRegs < reg){
				break;
			}
			(this->*pr->fun_read)(pucRegBuffer);
            len = reg*2;
			pucRegBuffer+=len;
			usNRegs-=reg;
			usAddress+=reg;
			if (usNRegs==0)
				return MB_ENOERR;
		}
	}
	return MB_ENOREG;

}

eMBErrorCode MBRegHandler::eMBRegDiscreteCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNDiscrete)
{
    uint8_t  index = 0;

	const DISCRETE_INPUT *pr=mb_tab_discrete_reg;
    * pucRegBuffer = 0;
	for ( pr=mb_tab_discrete_reg ; pr->reg_no>0 ; pr++){

		if (usAddress == pr->reg_no){
			if (pr->fun_read)
				*pucRegBuffer |= ((this->*pr->fun_read)()<<index);
			usNDiscrete--;
			usAddress++;
            index ++;
            if(index==8){
                index = 0;
                pucRegBuffer++;
                *pucRegBuffer = 0;
            }
			if (usNDiscrete==0)
				return MB_ENOERR;
		}
	}
    return MB_ENOREG;
}

eMBErrorCode MBRegHandler::eMBRegHoldingCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode)
{
    eMBErrorCode    eStatus = MB_ENOERR;
    uint8_t  reg, i;
    int len;

    const HOLDING_REG *pr=mb_tab_holding_reg;

    if (eMode == MB_REG_WRITE){
		for ( i=0 ; pr->reg_no >0 ;i++, pr++){
			if (usAddress == pr->reg_no){
                reg=pr->size;

				if (usNRegs < reg)
					break;

				(this->*pr->fun_write)(pucRegBuffer);
				// controllare condizione di ritorno ???
                len=reg*2;
				pucRegBuffer+=len;
				usNRegs-=reg;
				usAddress+=reg;
				if (usNRegs==0)
					return MB_ENOERR;
			}
		}
    }
    else if (eMode == MB_REG_READ){
		for ( i=0 ;  pr->reg_no>0 ;i++, pr++){
			if (usAddress == pr->reg_no){
                reg=pr->size;
                if (usNRegs < reg){
					break;
				}
				(this->*pr->fun_read)(pucRegBuffer);

                len = reg*2;
				pucRegBuffer+=len;
				usNRegs-=reg;
				usAddress+=reg;
				if (usNRegs==0)
					return MB_ENOERR;
			}
		}
	}
    return MB_ENOREG;
}

eMBErrorCode MBRegHandler::eMBRegCoilsCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode)
{
	const SINGLE_COIL *pr;
	uint8_t  index = 0;

    if (eMode == MB_REG_WRITE){
        for ( pr=mb_tab_coil_reg; pr->reg_no>0; pr++){
            if (usAddress == pr->reg_no){
                if (pr->fun_write)
                    (this->*pr->fun_write)((*pucRegBuffer>>index)&0x01);
                    //*pucRegBuffer |= (pr->fun_read()<<index);
                usNCoils--;
                usAddress++;
                index ++;
                if(index==8){
                    index = 0;
                    pucRegBuffer++;
                    *pucRegBuffer = 0;
                }
                if (usNCoils==0)
                    return MB_ENOERR;
            }
        }
    }
    else if (eMode == MB_REG_READ){
        * pucRegBuffer = 0;
		for ( pr=mb_tab_coil_reg; pr->reg_no>0; pr++){
            if (usAddress == pr->reg_no){
                if (pr->fun_read)
                    *pucRegBuffer |= ((this->*pr->fun_read)()<<index);
                usNCoils--;
                usAddress++;
                index ++;
                if(index==8){
                    index = 0;
                    pucRegBuffer++;
                    *pucRegBuffer = 0;
                }
                if (usNCoils==0)
                    return MB_ENOERR;
            }
        }
	}
    return MB_ENOREG;
}

void MBRegHandler::MB_getFloatNet(uint8_t *reg)
{
    float_to_buf(mScaleAdaptor->floatNet(),reg);
}

void MBRegHandler::MB_getFloatTare(uint8_t *reg)
{
    float_to_buf(mScaleAdaptor->floatTare(),reg);
}

void MBRegHandler::MB_getFloatGross(uint8_t *reg)
{
    float_to_buf(mScaleAdaptor->floatGross(),reg);
}

void MBRegHandler::MB_getFloatFull(uint8_t *reg)
{
    float_to_buf(mScaleAdaptor->getMax(),reg);
}

void MBRegHandler::MB_getLongFull(uint8_t *reg)
{
    long_to_buf(mScaleAdaptor->getMax()*expTab[mScaleAdaptor->getDeci()],reg);
}

void MBRegHandler::MB_getDevAddr(uint8_t *reg)
{
    short_to_buf(mDevAddr,reg);
}

void MBRegHandler::MB_setDevAddr(const uint8_t *reg)
{
    uint8_t dev_addr = buf_to_short(reg);
    emit sSetDevAddr(dev_addr);
}

void MBRegHandler::MB_getFloatHi(uint8_t *reg)
{
    float_to_buf(mHi,reg);
}

void MBRegHandler::MB_setFloatHi(const uint8_t *reg)
{
    mHi = buf_to_float(reg);
    emit sSetHi(mHi);
}

void MBRegHandler::MB_getFloatLo(uint8_t *reg)
{
    float_to_buf(mLow,reg);
}

void MBRegHandler::MB_setFloatLo(const uint8_t *reg)
{
    mLow = buf_to_float(reg);
    emit sSetLow(mLow);
}

void MBRegHandler::MB_getScaleSatus(uint8_t *reg)
{
    short da = mScaleAdaptor->stabFlag();
    if(mScaleAdaptor->zeroFlag())        da |= ((0x01)<<1);
    if(mScaleAdaptor->tareFlag())        da |= ((0x01)<<2);
    if(mScaleAdaptor->overFlag()/*errLoadType()==Scale::OVERLOAD*/)    da |= ((0x01)<<3);
    if(mChkRslt==CHECK_LOW)  da |= ((0x01)<<4);
    if(mChkRslt==CHECK_OK)  da |= ((0x01)<<5);
    if(mChkRslt==CHECK_HI)  da |= ((0x01)<<6);
    if(mCalSuccess)  da |= ((0x01)<<7);
    short_to_buf(da,reg);
}

void MBRegHandler::MB_setFloatTare(const uint8_t *reg)
{
    float t = buf_to_float(reg);
    emit sPretare(t);
}

void MBRegHandler::MB_getDeci(uint8_t *reg)
{
    short_to_buf(mScaleAdaptor->getDeci(),reg);
}

//void MBRegHandler::MB_setDeci(const uint8_t *reg)
//{
//    uint8_t deci = buf_to_short(reg);
//    emit sSetDeci(deci);
//}

void MBRegHandler::MB_getDiv(uint8_t *reg)
{
    short_to_buf(mScaleAdaptor->getDivi(),reg);
}

void MBRegHandler::MB_getUnit(uint8_t *reg)
{
    short_to_buf(mScaleAdaptor->getUnitIndex(),reg);
}

void MBRegHandler::MB_getLongNet(uint8_t *reg)
{
    long_to_buf(mScaleAdaptor->floatNet()*expTab[mScaleAdaptor->getDeci()],reg);
}

void MBRegHandler::MB_getLongTare(uint8_t *reg)
{
    long_to_buf(mScaleAdaptor->floatTare()*expTab[mScaleAdaptor->getDeci()],reg);
}

void MBRegHandler::MB_getLongGross(uint8_t *reg)
{
    long_to_buf(mScaleAdaptor->floatGross()*expTab[mScaleAdaptor->getDeci()],reg);
}

void MBRegHandler::MB_setDiv(const uint8_t *reg)
{

}


void MBRegHandler::MB_setEndian(uint8_t reg)
{
    if(mEndian!=reg){
        mEndian = (EndianMode)reg;
        TSettings set(DIR_SETTINGS,TSettings::IniFormat);
        set.beginGroup(MODBUS_GRP);
        set.setValue(ENDIAN_MODE,mEndian);
    }
}

uint8_t MBRegHandler::MB_getEndian(void){
    return mEndian;
}

void MBRegHandler::MB_setCalWgt(const uint8_t *reg)
{
    float w = buf_to_float(reg);
    emit sSetAdw(w);
}

void MBRegHandler::MB_getCalWgt(uint8_t *reg)
{
    float_to_buf(mScaleAdaptor->getAdw(),reg);
}

uint8_t MBRegHandler::MB_getStabFlag()
{
    return mScaleAdaptor->stabFlag();
}

uint8_t MBRegHandler::MB_getZeroFlag()
{
    return mScaleAdaptor->zeroFlag();
}

uint8_t MBRegHandler::MB_getTareFlag()
{
    return mScaleAdaptor->tareFlag();
}



void MBRegHandler::MB_setTareFlag(uint8_t reg){
    if(reg){
        emit sTare(1);
    }
    else{
        emit sTare(0);
    }
}



void MBRegHandler::MB_setZeroFlag(uint8_t reg){
    if(reg){
        emit sZero();
    }
}

uint8_t MBRegHandler::MB_getOverLoadFlag(void){
    //return mScale->errLoadType()==Scale::OVERLOAD;
    return mScaleAdaptor->overFlag();
}

uint8_t MBRegHandler::MB_getLoFlag(void){
    return mChkRslt==CHECK_LOW;
}

uint8_t MBRegHandler::MB_getOkFlag(void)
{
    return mChkRslt==CHECK_OK;
}
uint8_t MBRegHandler::MB_getHiFlag(void){
    return (mChkRslt==CHECK_HI);
}

uint8_t MBRegHandler::MB_getCalSuccess(void){
    return (uint8_t)(mCalSuccess);
}

//discrete_reg

//uint8 MB_getScaleFlag(void){
//    uint8 flag=0;
//    if(TareFlag(pScale)){
//        flag|=0x01;
//    }
//    if(ZeroFlag(pScale)){
//        flag<<=1;
//        flag|=0x01;
//    }
//    if(StabFlag(pScale)){
//        flag<<=1;
//        flag|=0x01;
//    }
//    return flag;
//}
//






const uint32_t MBRegHandler::expTab[]={1,10,100,1000,10000};

void MBRegHandler::float_to_buf(float a,uint8_t *buf)
{
    if(mEndian==ENDIAN_MODE_SMALL){
        memcpy(buf,&a,sizeof(float));
    }
    else
    {
        uint8_t *src = (uint8_t*)&a;
        buf[0] = src[3];
        buf[1] = src[2];
        buf[2] = src[1];
        buf[3] = src[0];
    }

}

void MBRegHandler::long_to_buf(long a,uint8_t *buf)
{
    if(mEndian==ENDIAN_MODE_SMALL){
        memcpy(buf,&a,sizeof(long));
    }
    else
    {
        uint8_t *src = (uint8_t*)&a;
        buf[0] = src[3];
        buf[1] = src[2];
        buf[2] = src[1];
        buf[3] = src[0];
    }

}

void MBRegHandler::short_to_buf(short a,uint8_t *buf)
{
    if(mEndian==ENDIAN_MODE_SMALL){
        memcpy(buf,&a,sizeof(short));
    }
    else
    {
        uint8_t *src = (uint8_t*)&a;
        buf[0] = src[1];
        buf[1] = src[0];
    }

}

short MBRegHandler::buf_to_short(const uint8_t *buf)
{
    short a;
    if(mEndian==ENDIAN_MODE_SMALL){
        memcpy(&a,buf,sizeof(short));
    }
    else
    {
        uint8_t *dest = (uint8_t*)&a;
        dest[0] = buf[1];
        dest[1] = buf[0];
    }
    return a;
}

long MBRegHandler::buf_to_long(const uint8_t *buf)
{
    long a;
    if(mEndian==ENDIAN_MODE_SMALL){
        memcpy(&a,buf,sizeof(long));
    }
    else
    {
        uint8_t *dest = (uint8_t*)&a;
        dest[0] = buf[3];
        dest[1] = buf[2];
        dest[2] = buf[1];
        dest[3] = buf[0];
    }
    return a;
}

float MBRegHandler::buf_to_float(const uint8_t *buf)
{
    float a;
    if(mEndian==ENDIAN_MODE_SMALL){
        memcpy(&a,buf,sizeof(long));
    }
    else
    {
        uint8_t *dest = (uint8_t*)&a;
        dest[0] = buf[3];
        dest[1] = buf[2];
        dest[2] = buf[1];
        dest[3] = buf[0];
    }
    return a;
}

void MBRegHandler::setAdw(float adw)
{
     mCalSuccess = mScaleAdaptor->setAdw(adw);
     TSettings set(DIR_SETTINGS,TSettings::IniFormat);
     set.beginGroup(MODBUS_GRP);
     set.setValue(CAL_SUCCESS,mCalSuccess);
}




void MBRegHandler::setHi(float hi)
{
    mHi = hi;
    ((MainWidget*)parent())->setHi(hi);
}

void MBRegHandler::setLow(float low)
{
    mLow = low;
    ((MainWidget*)parent())->setLow(low);
}

void MBRegHandler::setDevAddr(uint8_t dev)
{
    mDevAddr = dev;
}
